/**
 * Universidad Del Valle De Guatemala.
 * Algoritmos y Estructuras de Datos.
 * Sección 20.
 * Miguel Enrique Zea Arenales.
 * Carné 09238.
 * Hoja de Trabajo 8.
 * 08/11/2012
 */
package shortestpath;

import java.util.ArrayList;

/**
 * Implementación de un grafo con/sin dirección por medio de matrices de 
 * adyacencia.
 */
public class GraphMatrix<V,E> implements Graph<V,E> {
    private int dimension, Indices; // Dimension del grafo número actual de los vértices.
    private int[][] adjMatrix; // Matriz de adyacencia asociada al grafo.
    private ArrayList<V> Vertices = new ArrayList<>(); // Lista de vértices contenidos en el grafo.
    private ArrayList<E> Edges = new ArrayList<>(); // Lista de arcos presentes en el grafo.
    private boolean direction; // Especifica si el grafo es dirigido o no.
    
    /**
     * Pre: ninguna.
     * Post: se crea un grafo y su matriz de adyacencia de tamaño especificado, al
     * igual que se especifica el valor considerado para una NO conexión y si la
     * relación es bidireccional.
     */
    public GraphMatrix(int s, int defweight, boolean dir) {
        assert(s > 0):
        this.dimension = s;
        this.direction = dir;
        this.adjMatrix = new int[s][s];
        for(int i = 0; i < s; i++) {
            for(int j = 0; j < s; j++) {
                this.adjMatrix[i][j] = defweight;
            }
        }
        this.Indices = 0;
    }
    
    /**
     * Pre: los índices deben de estar dentro de los límites de la matriz.
     * Post: se coloca el peso de la conexión entre 2 vértices en la posición de
     * la matriz de adyacencia correspondiente.
     */
    public void setMatrixEntry(int i, int j, int value) {
        assert(value >= 0);
        assert(i < this.dimension);
        assert(j < this.dimension);
        this.adjMatrix[i][j] = value;
    }
    
    /**
     * Pre: ninguna.
     * Post: se obtiene la matriz de adyacencia asociada al grafo.
     */
    public int[][] getAdjacencyMatrix() {
        return this.adjMatrix;
    }
    
    /**
     * Pre: ninguna.
     * Post: se obtiene el índice del último vértice ingresado.
     */
    public int getIndices() {
        return this.Indices;
    }
    
    /**
     * Pre: debe existir por lo menos un vértice dentro de un grafo.
     * Post: se retorna la lista de vértices contenidos en el grafo.
     */
    public ArrayList<V> getVertices() {
        return Vertices;
    }
    
    /**
     * Pre: ninguna.
     * Post: se obtiene la lista de arcos presentes en el grafo. 
     */
    public ArrayList<E> getEdges() {
        return Edges;
    }
    
    /**
     * Pre: ninguna.
     * Post: se agrega un vértice al grafo. 
     */
    @Override
    public void add(V label) {
        assert(this.Indices < dimension);
        this.Vertices.add(label);
        Indices++;
    }
    
    /**
     * Pre: ninguna.
     * Post: se establece un arco dentro del grafo.
     */
    @Override
    public void addEdge(E label) {
        this.Edges.add(label);
    }
    
    /**
     * Pre: ninguna.
     * Post: se retorna el número de vértices contenidos en el grafo.
     */
    @Override
    public int size() {
        return this.Vertices.size();
    }
    
    /**
     * Pre: ninguna.
     * Post: retorna verdadero si y sólo si el grafo no continene ningún vértice.
     */
    @Override
    public boolean isEmpty() {
        return this.Vertices.isEmpty();
    }
    
    /**
     * Pre: ninguna.
     * Post: retorna verdadero si y sólo si el grafo es dirigido.
     */
    @Override
    public boolean isDirected() {
        return this.Vertices.isEmpty();
    }
    
    /**
     * Pre: ninguna.
     * Post: se eliminan los contenidos del grafo.
     */
    @Override
    public void clear() {
        this.adjMatrix = new int[this.dimension][this.dimension];
    }
    
    /**
     * Pre: el grafo debe contener por lo menos un vértice.
     * Post: retorna verdadero si y sólo si el vértice especificado existe 
     * dentro del nodo.
     */
    @Override
    public boolean contains(V label) {
        return this.Vertices.contains(label);
    }
}
